/**
 * 
 */
package com.wbcs.jbsf.auth.abs;

import java.io.IOException;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import com.wbcs.jbsf.bean.Role;
import com.wbcs.jbsf.dao.IDataModal;
import com.wbcs.jbsf.dao.JBSFDaoTemplate;
import com.wbcs.jbsf.format.IFormat;
import com.wbcs.jbsf.format.impl.URLPrjnameAddFormat;
import com.wbcs.jbsf.format.impl.WbcsPageId2UrlFormat;
import com.wbcs.jbsf.modal.abs.AbsTableModal;
import com.wbcs.jbsf.modal.abs.AbsTableSpaceModal;
import com.wbcs.jbsf.util.Consts;
import com.wbcs.jbsf.util.Server2Client;
import com.wbcs.jbsf.util.Wbcs4JBSFUtil;
import com.wbcs.system.WbcsResponse;

/**
 * 标准登录流程
 * @author hawkfly
 */
public abstract class AbstandLogin
{
    private Log log = LogFactory.getLog(AbstandLogin.class);
    protected HttpServletRequest request;
    protected HttpServletResponse response;
    protected final String CONTINUE = Consts.CONTINUE;
    private RequestStatus requestStatus;
    protected JBSFDaoTemplate jdaoTemplate = new JBSFDaoTemplate(false);
    private String sendredirecturl;
    private boolean isAdmin;
    private WbcsResponse wbcsresponse;
    
    public AbstandLogin(ServletRequest rq, ServletResponse rp){
        if(rq instanceof HttpServletRequest){
            request = (HttpServletRequest)rq;
        }
        if(rp instanceof HttpServletResponse){
            response = (HttpServletResponse)rp;
        } 
    }
    
    /**
     * 标准登录流程
     * @return 消息体 默认为CONTINUE
     * @throws SQLException 
     */
    public String doLogin() throws SQLException{
        String exceptionMsg = null;
        if(!checkResource())return doErrorMsg("资源未准备好，请检查是否将request和requestStatus对象正确注入！");
        if(CONTINUE.equals(exceptionMsg = checklogin())){
            if(!CONTINUE.equals(exceptionMsg = loadUserAuthes()))return doErrorMsg(exceptionMsg);
            switch(requestStatus){
               case http://跳转页面的权限检测并封装菜单到request中,执行页面跳转
                   if(!CONTINUE.equals(exceptionMsg = doForward(RequestStatus.http)))
                       return doErrorMsg(exceptionMsg);
                   break;
               case ajax://读取本页面菜单，根据类型封装数据发回给页面
                   if(!CONTINUE.equals(exceptionMsg = doForward(RequestStatus.ajax)))
                       return doErrorMsg(exceptionMsg);
                   break;
               case wbcs://不做任何处理，交给wbcs pageInterceptor进行全权处理
                   if(!CONTINUE.equals(exceptionMsg = doForward(RequestStatus.wbcs)))
                       return doErrorMsg(exceptionMsg);
                   break;
               default://用户注入的requestStatus为无效值
                   return doErrorMsg("注入的requestStatus编码无效，请给出RequestStatus枚举中的值！");
            }
            
        }else{
            return exceptionMsg;
        }
        return CONTINUE;
    }
    
    /**
     * 登录检测(J2EE和WBCS)
     * 登录成功的情况下需存储用户名及真实名到session中
     */
    public abstract String checklogin() throws SQLException;
    
    /**
     * 将用户角色编号，角色名称及用户的所有权限加载到session中
     * 处理异常，如果存在异常情况请直接返回异常字符串，否则返回系统提供的CONTINUE常量
     * @return 消息体 默认为CONTINUE
     * @throws SQLException 
     */
    public String loadUserAuthes() throws SQLException{
        final HttpSession session = request.getSession();
        Object userid = session.getAttribute(Consts.SESSION_USERID);
        //role list to session
        String rolesql = "SELECT ru.roleid, r.rolename, r.isghost, r.isadmin FROM jbsf_user_roles ru, jbsf_roles r where ru.roleid = r.id and ru.userid=? and r.isghost <> 1";
        List<Role> lstroles = jdaoTemplate.select(rolesql,new IDataModal<List<Role>>(){
            public List<Role> loadDatas(ResultSet rs,int ccount,ResultSetMetaData rmd,List<Role> dataModal) throws SQLException
            {
                dataModal = new ArrayList<Role>();
                while(rs.next()){
                    Role role = new Role();
                    role.setRolecode(rs.getString(1));
                    role.setRolename(rs.getString(2));
                    role.setGhost(Consts.DB_YES.equals(rs.getString(3))?true:false);
                    role.setAdmin(Consts.DB_YES.equals(rs.getString(4))?true:false);
                    dataModal.add(role);
                    if(Consts.DB_YES.equals(rs.getString(4))) markAdmin(true);
                }
                return dataModal;
            }},userid);
        if(lstroles.size() == 0)return "未为本用户指定角色！";
        session.setAttribute(Consts.SESSION_ROLE, lstroles);
        //httpauthes and wbcsauthes to session
        List<String> rolecodes = Wbcs4JBSFUtil.roles2lstrolecodes(lstroles, true);//排除掉admin后的业务角色
        Map<String, AbsTableModal> authes = null;
        if(rolecodes.size() != 0){//具有非管理员角色
            StringBuffer authsql = new StringBuffer("SELECT * FROM jbsf_roles_authes ra, jbsf_authorize a where ra.authid = a.id and ra.roleid in(")
                                    .append(Wbcs4JBSFUtil.lst2dotaskStr(rolecodes.size())).append(")");
            authes = jdaoTemplate.select(authsql.toString(),new IDataModal<Map<String, AbsTableModal>>(){
                public Map<String,AbsTableModal> loadDatas(ResultSet rs,int ccount,ResultSetMetaData rmd,Map<String,AbsTableModal> dataModal)
                        throws SQLException
                {
                    Map<String,AbsTableModal> map = new HashMap<String, AbsTableModal>();
                    AbsTableModal httpauthes = new AbsTableModal(Consts.SESSION_HTTPAUTHES, "URL"){};
                    AbsTableModal wbcsauthes = new AbsTableModal(Consts.SESSION_WBCSAUTHES, "CODE"){};
                    map.put(Consts.SESSION_HTTPAUTHES,httpauthes); map.put(Consts.SESSION_WBCSAUTHES,wbcsauthes);
                    //正常权限获取
                    while(rs.next()){
                        String url = rs.getString("URL");
                        if(url != null){//http权限有效
                            httpauthes.newRow().setResultSet(rs).addCols(new String[]{"ID","PID","NAME","TYPE","URL","TARGET","ORDERNUM","ICON1","ACCESSTYPE","DISPLAY"});
                        }else{//wbcs权限有效
                            wbcsauthes.newRow().setResultSet(rs).addCols(new String[]{"ID","PID","NAME","TYPE","TARGET","ORDERNUM","ICON1","ACCESSTYPE","DISPLAY"});
                        }
                    }
                    return map;
                }},rolecodes);
        }
        if(authes == null){
            authes = new HashMap<String, AbsTableModal>();
        }
        //追加管理权限并存入会话
        if(isAdmin){
            AbsTableModal wbcsauthes = authes.get(Consts.SESSION_WBCSAUTHES);
            if(wbcsauthes == null) wbcsauthes = new AbsTableModal(Consts.SESSION_WBCSAUTHES, "CODE"){};
            try{
                wbcsauthes.addRows(Consts.AdminAuth.getAdminauthes().getAllMDatas());
            }finally{
                isAdmin = false;
            }
        }
        session.setAttribute(Consts.SESSION_HTTPAUTHES,authes.get(Consts.SESSION_HTTPAUTHES));
        session.setAttribute(Consts.SESSION_WBCSAUTHES,authes.get(Consts.SESSION_WBCSAUTHES));
        
        //httpmenus and wbcsmenus to session
        if(rolecodes.size() == 0)return CONTINUE;
        StringBuffer menusql = 
         new StringBuffer("SELECT ICON, LOCATIONCODE, PACKETYPE, (case when a.url is null then a.code else a.url end) MENUID, o.URL, o.CODE FROM (")
                  .append("SELECT pm.locationcode,pm.pageid,pm.menuid,pm.roleid,pm.icon, a.*, lt.id lid, lt.code lcode, lt.name lname, lt.type packetype ")
                  .append("FROM jbsf_page_menus pm, jbsf_authorize a, jbsf_locationtype lt where pm.pageid = a.id and pm.locationcode = lt.code and roleid in(")
                  .append(Wbcs4JBSFUtil.lst2dotaskStr(rolecodes.size())).append(")")
                  .append(")o, jbsf_authorize a where o.menuid=a.id");
        jdaoTemplate.select(menusql.toString(),new IDataModal<HttpSession>(){
            public HttpSession loadDatas(ResultSet rs,int ccount,ResultSetMetaData rmd,HttpSession dataModal)
                    throws SQLException
            {
                AbsTableSpaceModal httpmenus = new AbsTableSpaceModal(){};
                AbsTableSpaceModal wbcsmenus = new AbsTableSpaceModal(){};
                String[] menucolnames = {"PACKETYPE","MENUID","ICON","LOCATIONCODE"};
                while(rs.next()){
                    String url = rs.getString("URL");
                    if(url != null){//http菜单
                        AbsTableModal httptable = httpmenus.getTable(url);
                        if(httptable == null){//新页面
                            httptable = httpmenus.newTable(url);
                        }
                        //httptable.newRow().setResultSet(rs).addCols(menucolnames);
                        httptable.newRow().setResultSet(rs).setColnames(menucolnames)
                            .setColFormat(new String[]{"MENUID"},new IFormat[]{new WbcsPageId2UrlFormat(), new URLPrjnameAddFormat()});
                    }
                    else{//wbcs菜单
                        String code = rs.getString("CODE");
                        AbsTableModal wbcstable = wbcsmenus.getTable(code);
                        if(wbcstable == null){
                            wbcstable = wbcsmenus.newTable(code);
                        }
                        //wbcstable.newRow().setResultSet(rs).addCols(menucolnames);
                        wbcstable.newRow().setResultSet(rs).setColnames(menucolnames)
                            .setColFormat(new String[]{"MENUID"},new IFormat[]{new WbcsPageId2UrlFormat(), new URLPrjnameAddFormat()});
                    }
                }
                session.setAttribute(Consts.SESSION_HTTPMENUS,httpmenus);
                session.setAttribute(Consts.SESSION_WBCSMENUS,wbcsmenus);
                return session;
            }},rolecodes);
        
        return CONTINUE;
    }
    
    /**
     * 路由转接
     * 具体的权限处理将视情况在filter或者interceptor中处理
     * @return 消息体 默认为CONTINUE
     */
    public String doForward(RequestStatus authkey){
        if(RequestStatus.http.equals(authkey)){//http提交形式处理
            String checkPageKey = request.getParameter("redirecturl");
            try
            {
                request.getRequestDispatcher(checkPageKey).forward(request,response);//-->FILTER-->PAGE
            }catch(ServletException e)
            {
                e.printStackTrace();
            }catch(IOException e)
            {
                e.printStackTrace();
            }
        }   
        else if(RequestStatus.ajax.equals(authkey)){//ajax提交形式处理,不走filter
            String checkPageKey = request.getParameter("requestpageuri");
            //在session中读到菜单数据
            Object menusObj = request.getSession().getAttribute(Consts.SESSION_HTTPMENUS);
            if(menusObj == null)return "会话中无菜单配置";
            AbsTableSpaceModal menus = (AbsTableSpaceModal)menusObj;
            AbsTableModal menusTableModal = menus.getTable(checkPageKey);
            //封装菜单到指定格式
            //response回写
            Wbcs4JBSFUtil.toclientPacket4TS(menusTableModal.parseLst2Maplst("LOCATIONCODE"), new Server2Client(request, response));
        }
        else if(RequestStatus.wbcs.equals(authkey)){
            if(sendredirecturl != null)
            {
                wbcsresponse.sendRedirect(sendredirecturl);//sendredirecturl
            }
            else
            {
                return "执行wbcs登录请求但没有注入转发页面地址！";
            }
        }
        return CONTINUE;
    }
    
    public void markAdmin(boolean isadmin){
        if(isadmin){//是管理员
            this.isAdmin = isadmin;
            request.getSession().setAttribute(Consts.SESSION_ISADMIN,true);
        }
    }
    
    public boolean checkResource(){
        if(request != null && response != null && requestStatus != null)return true;
        else return false;
    }
    
    public AbstandLogin addRequestStatus(RequestStatus requestStatus){
        this.requestStatus = requestStatus;
        return this;
    }
    
    public enum RequestStatus{
        ajax, http, wbcs;
    }
    
    private String doErrorMsg(String msg){
        log.error(msg);
        return msg;
    }

    public AbstandLogin setSendredirecturl(String sendredirecturl)
    {
        this.sendredirecturl=sendredirecturl;
        return this;
    }

    public AbstandLogin setWbcsresponse(WbcsResponse wbcsresponse)
    {
        this.wbcsresponse=wbcsresponse;
        return this;
    }
}

